/*
 * $Id: PlanFirstLevelManager.java 8 2012-04-28 05:11:23Z forwardly@gmail.com $
 * 
 * Copyright (c) 2001-2008 Accentrix Company Limited. All Rights Reserved.
 * 
 * Accentrix Company Limited. ("Accentrix") retains copyright on all text, source
 * and binary code contained in this software and documentation. Accentrix grants
 * Licensee a limited license to use this software, provided that this copyright
 * notice and license appear on all copies of the software. The software source
 * code is provided for reference purposes only and may not be copied, modified 
 * or distributed.
 * 
 * THIS SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS," WITHOUT ANY WARRANTY OF
 * ANY KIND UNLESS A SEPARATE WARRANTIES IS PURCHASED FROM ACCENTRIX AND REMAINS
 * VALID.  ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. ACCENTRIX SHALL NOT BE LIABLE
 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING OR MODIFYING THE
 * SOFTWARE OR ITS DERIVATIVES.
 * 
 * IN NO EVENT WILL ACCENTRIX BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
 * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES,
 * HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE
 * USE OF OR INABILITY TO USE SOFTWARE, EVEN IF ACCENTRIX HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */
package com.lightsaber.trade.as.service.planfirst;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springside.modules.orm.Page;

import com.lightsaber.trade.as.dao.category.CategoryDao;
import com.lightsaber.trade.as.dao.planning.CategoryPlanningItemDao;
import com.lightsaber.trade.as.dao.planning.Level1PlanningDao;
import com.lightsaber.trade.as.dao.planning.PlanningDao;
import com.lightsaber.trade.as.entity.category.Category;
import com.lightsaber.trade.as.entity.category.CategoryNode;
import com.lightsaber.trade.as.entity.planning.Level1Planning;
import com.lightsaber.trade.as.entity.planning.Planning;
import com.lightsaber.trade.as.entity.planning.PlanningLevel;
import com.lightsaber.trade.as.entity.planning.PlanningStatus;
import com.lightsaber.trade.core.dao.BaseDao;
import com.lightsaber.trade.core.entity.AuditedObject;
import com.lightsaber.trade.core.entity.BaseEntity;
import com.lightsaber.trade.core.service.BaseServiceImpl;

@Service
@Transactional
public class PlanFirstLevelManager extends BaseServiceImpl<Level1Planning, String> {
    private final static Logger log = LoggerFactory.getLogger(PlanFirstLevelManager.class);

    @Autowired
    Level1PlanningDao level1PlanningDao;
    @Autowired
    CategoryDao categoryDao;

    @Autowired
    CategoryPlanningItemDao categoryPlanningItemDao;

    @Autowired
    PlanningDao planningDao;

    @Override
    protected BaseDao<Level1Planning, String> getDao() {
        return level1PlanningDao;
    }

    public void findPage(final Page<Level1Planning> page, final String[] categoryIds) {
        level1PlanningDao.findPage(page, categoryIds);

    }

    @Override
    public void save(final Level1Planning level1Planning) {
        level1Planning.setStatus(PlanningStatus.WaitingForSubmission);
        Category category = categoryDao.get(level1Planning.getCategory().getId());

        if (StringUtils.isBlank(level1Planning.getId())) {
            level1Planning.setCategory(category);
            super.save(level1Planning);

        } else {
            Level1Planning oldLevel1Planning = get(level1Planning.getId());

            BeanUtils.copyProperties(level1Planning, oldLevel1Planning, new String[] {
                    BaseEntity.ID, BaseEntity.VERSION, AuditedObject.CREATED_BY,
                    AuditedObject.CREATED_DATE, "category" });
            oldLevel1Planning.setCategory(category);

            super.update(oldLevel1Planning);
        }
    }

    public void conifirmForEndorsement(final Level1Planning level1Planning) throws Exception {
        Level1Planning oldLevel1Planning = get(level1Planning.getId());

        oldLevel1Planning.setStatus(PlanningStatus.WaitingForEndorsement);

        super.update(oldLevel1Planning);

        this.checkStatusOfLevel1PlannigOfMasterTree(oldLevel1Planning.getCategory().getPlanYear());
    }

    private void checkStatusOfLevel1PlannigOfMasterTree(final Integer planYear) throws Exception {
        Category mastTree = categoryDao.findMasterTreeByPlanYear(planYear);

        boolean hasAnyNotSubmitedBranchTree = recursionCheck(mastTree.getRoot());

        if (!hasAnyNotSubmitedBranchTree) {
            Planning planning = planningDao.findByPlanningExerciseAndLevel(planYear,
                    PlanningLevel.FirstLevel);

            planning.setStatus(PlanningStatus.WaitingForEndorsement);

            planningDao.save(planning);
        }
    }

    private boolean recursionCheck(final CategoryNode node) {
        if (node.getOwnedBranchTrees().size() > 0) {

            Level1Planning level1Planning = null;

            boolean hasWaiting = false;

            for (Category category : node.getOwnedBranchTrees()) {
                level1Planning = level1PlanningDao.findByBranchTree(category);

                if (level1Planning != null
                        && level1Planning.getStatus() == PlanningStatus.WaitingForEndorsement) {

                    hasWaiting = true;
                    break;
                }
            }

            if (!hasWaiting) {
                return true;
            }

        }

        for (CategoryNode child : node.getChildren()) {
            if (recursionCheck(child)) {
                return true;
            }
        }

        return false;
    }

    public List<Level1Planning> findByCategoryId(final String categoryId) {
        return level1PlanningDao.findBy("category.id", categoryId);
    }

    public boolean hasNameByCategory(final Level1Planning level1Planning) {
        Category category = categoryDao.get(level1Planning.getCategory().getId());
        CategoryNode ownerNode = category.getOwnerNode();

        log.debug("Owner node id ={}", ownerNode.getId());

        long cnt = level1PlanningDao.countNameByCategoryId(level1Planning.getId(),
                level1Planning.getName(), ownerNode);

        if (cnt > 0) {
            return true;
        }
        return false;
    }

    public Level1Planning findByBranchTree(final String branchTreeId) {
        return level1PlanningDao.findByBranchTree(branchTreeId);
    }

}
